using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 审计日志应用服务实现
    /// 提供审计日志的完整业务逻辑，包括记录、查询、统计和管理功能
    /// </summary>
    public class AuditLogAppService : IAuditLogAppService
    {
        private readonly IAuditLogRepository _auditLogRepository;
        private readonly ILogger<AuditLogAppService> _logger;

        public AuditLogAppService(
            IAuditLogRepository auditLogRepository,
            ILogger<AuditLogAppService> logger)
        {
            _auditLogRepository = auditLogRepository;
            _logger = logger;
        }

        /// <summary>
        /// 获取所有审计日志
        /// </summary>
        /// <returns>审计日志列表</returns>
        public async Task<IEnumerable<AuditLogDto>> GetAllAsync()
        {
            try
            {
                _logger.LogDebug("Getting all audit logs");
                var entities = await _auditLogRepository.GetAllAsync();
                var result = entities.Select(MapToDto).ToList();
                
                _logger.LogInformation("Retrieved {Count} audit logs", result.Count);
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting all audit logs");
                throw;
            }
        }

        /// <summary>
        /// 根据ID获取审计日志
        /// </summary>
        /// <param name="id">审计日志标识符</param>
        /// <returns>审计日志信息</returns>
        public async Task<AuditLogDto?> GetByIdAsync(long id)
        {
            try
            {
                if (id <= 0)
                {
                    _logger.LogWarning("Invalid audit log id: {Id}", id);
                    return null;
                }

                _logger.LogDebug("Getting audit log by id {Id}", id);
                var entity = await _auditLogRepository.GetByIdAsync(id);
                
                if (entity == null)
                {
                    _logger.LogWarning("Audit log not found with id {Id}", id);
                    return null;
                }

                return MapToDto(entity);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting audit log by id {Id}", id);
                throw;
            }
        }

        /// <summary>
        /// 添加新的审计日志
        /// </summary>
        /// <param name="dto">审计日志数据传输对象</param>
        /// <returns>添加任务</returns>
        public async Task AddAsync(AuditLogDto dto)
        {
            try
            {
                if (dto == null)
                {
                    _logger.LogWarning("Cannot add null audit log");
                    throw new ArgumentNullException(nameof(dto));
                }

                _logger.LogDebug("Adding audit log: {Type} by {UserName}", dto.Type, dto.UserName);

                var entity = new AuditLog
                {
                    Type = dto.Type ?? string.Empty,
                    Content = dto.Content ?? string.Empty,
                    UserId = dto.UserId ?? string.Empty,
                    UserName = dto.UserName ?? string.Empty,
                    Timestamp = dto.Timestamp == default ? DateTime.UtcNow : dto.Timestamp,
                    IP = dto.IP ?? string.Empty,
                    Result = dto.Result ?? string.Empty,
                    Exception = dto.Exception ?? string.Empty,
                    Resource = dto.Resource ?? string.Empty
                };

                await _auditLogRepository.AddAsync(entity);
                _logger.LogInformation("Audit log added successfully: {Type} by {UserName}", dto.Type, dto.UserName);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error adding audit log");
                throw;
            }
        }

        /// <summary>
        /// 查询审计日志
        /// </summary>
        /// <param name="type">操作类型</param>
        /// <param name="userId">用户标识符</param>
        /// <param name="start">开始时间</param>
        /// <param name="end">结束时间</param>
        /// <param name="resource">资源名称</param>
        /// <returns>符合条件的审计日志列表</returns>
        public async Task<IEnumerable<AuditLogDto>> QueryAsync(string type, long userId, DateTime? start, DateTime? end, string resource = "")
        {
            try
            {
                _logger.LogDebug("Querying audit logs with type={Type}, userId={UserId}, start={Start}, end={End}, resource={Resource}", 
                    type, userId, start, end, resource);

                // 使用仓储层的优化查询方法
                var entities = await _auditLogRepository.QueryAsync(type, userId, start, end, resource);
                var result = entities.Select(MapToDto).ToList();

                _logger.LogInformation("Query returned {Count} audit logs", result.Count);
                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error querying audit logs");
                throw;
            }
        }

        /// <summary>
        /// 分页获取审计日志
        /// </summary>
        /// <param name="pageIndex">页索引，从1开始</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="type">操作类型过滤</param>
        /// <param name="userId">用户ID过滤</param>
        /// <param name="resource">资源过滤</param>
        /// <returns>分页结果</returns>
        public async Task<(List<AuditLogDto> Items, int TotalCount)> GetPagedAsync(
            int pageIndex = 1, 
            int pageSize = 20, 
            string? type = null, 
            string? userId = null, 
            string? resource = null)
        {
            try
            {
                if (pageIndex <= 0) pageIndex = 1;
                if (pageSize <= 0 || pageSize > 100) pageSize = 20;

                _logger.LogDebug("Getting paged audit logs: page={PageIndex}, size={PageSize}", pageIndex, pageSize);

                var repository = _auditLogRepository as Infrastructure.Repositories.AuditLogRepository;
                if (repository != null)
                {
                    var (items, totalCount) = await repository.GetPagedAsync(pageIndex, pageSize, type, userId, resource);
                    var dtos = items.Select(MapToDto).ToList();

                    _logger.LogInformation("Retrieved page {PageIndex} with {Count} items, total {TotalCount}", 
                        pageIndex, dtos.Count, totalCount);

                    return (dtos, totalCount);
                }

                // Fallback to basic implementation
                var allEntities = await _auditLogRepository.GetAllAsync();
                var query = allEntities.AsQueryable();

                if (!string.IsNullOrEmpty(type))
                    query = query.Where(x => x.Type.Contains(type));
                if (!string.IsNullOrEmpty(userId))
                    query = query.Where(x => x.UserId == userId);
                if (!string.IsNullOrEmpty(resource))
                    query = query.Where(x => x.Resource.Contains(resource));

                var total = query.Count();
                var pagedItems = query
                    .Skip((pageIndex - 1) * pageSize)
                    .Take(pageSize)
                    .Select(MapToDto)
                    .ToList();

                return (pagedItems, total);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting paged audit logs");
                throw;
            }
        }

        /// <summary>
        /// 获取审计日志统计信息
        /// </summary>
        /// <returns>统计信息</returns>
        public async Task<AuditLogStatisticsDto> GetStatisticsAsync()
        {
            try
            {
                _logger.LogDebug("Getting audit log statistics");

                var repository = _auditLogRepository as Infrastructure.Repositories.AuditLogRepository;
                if (repository != null)
                {
                    var dailyStats = await repository.GetStatisticsByDaysAsync(30);
                    var typeStats = await repository.GetStatisticsByTypeAsync();
                    var userStats = await repository.GetStatisticsByUserAsync(10);

                    var allLogs = await _auditLogRepository.GetAllAsync();
                    var totalCount = allLogs.Count();
                    
                    var todayCount = allLogs.Count(x => x.Timestamp.Date == DateTime.UtcNow.Date);
                    var weekCount = allLogs.Count(x => x.Timestamp >= DateTime.UtcNow.AddDays(-7));
                    var monthCount = allLogs.Count(x => x.Timestamp >= DateTime.UtcNow.AddDays(-30));

                    var stats = new AuditLogStatisticsDto
                    {
                        TotalCount = totalCount,
                        TodayCount = todayCount,
                        WeekCount = weekCount,
                        MonthCount = monthCount,
                        DailyStatistics = dailyStats,
                        TypeStatistics = typeStats,
                        UserStatistics = userStats
                    };

                    _logger.LogInformation("Generated audit log statistics: Total={Total}, Today={Today}, Week={Week}, Month={Month}", 
                        totalCount, todayCount, weekCount, monthCount);

                    return stats;
                }

                // Fallback to basic statistics
                var entities = await _auditLogRepository.GetAllAsync();
                var list = entities.ToList();

                return new AuditLogStatisticsDto
                {
                    TotalCount = list.Count,
                    TodayCount = list.Count(x => x.Timestamp.Date == DateTime.UtcNow.Date),
                    WeekCount = list.Count(x => x.Timestamp >= DateTime.UtcNow.AddDays(-7)),
                    MonthCount = list.Count(x => x.Timestamp >= DateTime.UtcNow.AddDays(-30)),
                    DailyStatistics = new Dictionary<string, int>(),
                    TypeStatistics = list.GroupBy(x => x.Type).ToDictionary(g => g.Key, g => g.Count()),
                    UserStatistics = list.Where(x => !string.IsNullOrEmpty(x.UserName))
                        .GroupBy(x => x.UserName)
                        .OrderByDescending(g => g.Count())
                        .Take(10)
                        .ToDictionary(g => g.Key, g => g.Count())
                };
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting audit log statistics");
                throw;
            }
        }

        /// <summary>
        /// 批量添加审计日志
        /// </summary>
        /// <param name="dtos">审计日志列表</param>
        /// <returns>添加任务</returns>
        public async Task BatchAddAsync(IEnumerable<AuditLogDto> dtos)
        {
            try
            {
                if (dtos == null || !dtos.Any())
                {
                    _logger.LogWarning("Cannot batch add null or empty audit logs");
                    return;
                }

                var entities = dtos.Select(dto => new AuditLog
                {
                    Type = dto.Type ?? string.Empty,
                    Content = dto.Content ?? string.Empty,
                    UserId = dto.UserId ?? string.Empty,
                    UserName = dto.UserName ?? string.Empty,
                    Timestamp = dto.Timestamp == default ? DateTime.UtcNow : dto.Timestamp,
                    IP = dto.IP ?? string.Empty,
                    Result = dto.Result ?? string.Empty,
                    Exception = dto.Exception ?? string.Empty,
                    Resource = dto.Resource ?? string.Empty
                }).ToList();

                _logger.LogDebug("Batch adding {Count} audit logs", entities.Count);

                var repository = _auditLogRepository as Infrastructure.Repositories.AuditLogRepository;
                if (repository != null)
                {
                    await repository.BatchAddAsync(entities);
                }
                else
                {
                    // Fallback to individual adds
                    foreach (var entity in entities)
                    {
                        await _auditLogRepository.AddAsync(entity);
                    }
                }

                _logger.LogInformation("Batch added {Count} audit logs successfully", entities.Count);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error batch adding audit logs");
                throw;
            }
        }

        /// <summary>
        /// 清理过期的审计日志
        /// </summary>
        /// <param name="retentionDays">保留天数</param>
        /// <returns>被清理的记录数</returns>
        public async Task<int> CleanupAsync(int retentionDays = 90)
        {
            try
            {
                if (retentionDays <= 0)
                {
                    _logger.LogWarning("Invalid retention days: {RetentionDays}", retentionDays);
                    throw new ArgumentException("Retention days must be greater than 0", nameof(retentionDays));
                }

                var cutoffDate = DateTime.UtcNow.AddDays(-retentionDays);
                _logger.LogDebug("Cleaning up audit logs before {CutoffDate}", cutoffDate);

                var repository = _auditLogRepository as Infrastructure.Repositories.AuditLogRepository;
                if (repository != null)
                {
                    var deletedCount = await repository.CleanupAsync(cutoffDate);
                    _logger.LogInformation("Cleaned up {Count} audit logs older than {Days} days", deletedCount, retentionDays);
                    return deletedCount;
                }

                _logger.LogWarning("Cleanup not supported by current repository implementation");
                return 0;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error cleaning up audit logs");
                throw;
            }
        }

        /// <summary>
        /// 记录操作审计日志的便捷方法
        /// </summary>
        /// <param name="operationType">操作类型</param>
        /// <param name="content">操作内容</param>
        /// <param name="userId">用户ID</param>
        /// <param name="userName">用户名</param>
        /// <param name="ip">IP地址</param>
        /// <param name="resource">操作资源</param>
        /// <param name="result">操作结果</param>
        /// <param name="exception">异常信息</param>
        /// <returns>记录任务</returns>
        public async Task LogOperationAsync(
            string operationType,
            string content,
            string? userId = null,
            string? userName = null,
            string? ip = null,
            string? resource = null,
            string result = "Success",
            string? exception = null)
        {
            try
            {
                var auditLog = new AuditLogDto
                {
                    Type = operationType,
                    Content = content,
                    UserId = userId ?? string.Empty,
                    UserName = userName ?? string.Empty,
                    IP = ip ?? string.Empty,
                    Resource = resource ?? string.Empty,
                    Result = result,
                    Exception = exception ?? string.Empty,
                    Timestamp = DateTime.UtcNow
                };

                await AddAsync(auditLog);
            }
            catch (Exception ex)
            {
                // 审计日志记录失败不应影响业务操作
                _logger.LogError(ex, "Error logging audit operation: {OperationType}", operationType);
            }
        }

        /// <summary>
        /// 将实体映射为DTO
        /// </summary>
        /// <param name="entity">审计日志实体</param>
        /// <returns>审计日志DTO</returns>
        private static AuditLogDto MapToDto(AuditLog entity)
        {
            return new AuditLogDto
            {
                Id = entity.Id,
                Type = entity.Type,
                Content = entity.Content,
                UserId = entity.UserId,
                UserName = entity.UserName,
                Timestamp = entity.Timestamp,
                IP = entity.IP,
                Result = entity.Result,
                Exception = entity.Exception,
                Resource = entity.Resource
            };
        }
    }

    /// <summary>
    /// 审计日志统计信息DTO
    /// </summary>
    public class AuditLogStatisticsDto
    {
        /// <summary>
        /// 总记录数
        /// </summary>
        public int TotalCount { get; set; }

        /// <summary>
        /// 今日记录数
        /// </summary>
        public int TodayCount { get; set; }

        /// <summary>
        /// 本周记录数
        /// </summary>
        public int WeekCount { get; set; }

        /// <summary>
        /// 本月记录数
        /// </summary>
        public int MonthCount { get; set; }

        /// <summary>
        /// 每日统计（日期 -> 数量）
        /// </summary>
        public Dictionary<string, int> DailyStatistics { get; set; } = new();

        /// <summary>
        /// 按类型统计（类型 -> 数量）
        /// </summary>
        public Dictionary<string, int> TypeStatistics { get; set; } = new();

        /// <summary>
        /// 按用户统计（用户名 -> 数量）
        /// </summary>
        public Dictionary<string, int> UserStatistics { get; set; } = new();
    }
}
